import pygame
import sys
import random
import math
import traceback

class Ball(pygame.sprite.Sprite):
    def __init__(self,Ball_image,green_image,position,speed,size,target):
        pygame.sprite.Sprite.__init__(self)
        
        self.Ball_image=pygame.image.load(Ball_image).convert_alpha()
        self.green_image=pygame.image.load(green_image).convert_alpha()
        self.rect=self.Ball_image.get_rect()
        self.rect.left,self.rect.top=position
        self.target=target
        self.speed=speed
        self.side= [random.choice([-1,1]),random.choice([-1,1])]
        self.width, self.height = size[0], size[1]
        #self.radius 是collide_circle方法中一定要有的半径参数
        self.radius =self.rect.width/2
        self.control = False
        self.collide=False
        
    def move(self):
        if self.control :
            self.rect = self.rect.move(self.speed)
        else:
            self.rect = self.rect.move([self.speed[0]*self.side[0],self.speed[1]*self.side[1]])
        
        if self.rect.right <0:
            self.rect.left=self.width
            
        elif self.rect.left > self.width:
            self.rect.right=0
            
        elif self.rect.bottom <0:
            self.rect.top=self.height
            
        elif self.rect.top > self.height:
            self.rect.bottom=0
    def check(self,motion):
        if self.target <motion<self.target+5:
            return True
        else:
            return False


class Glass(pygame.sprite.Sprite):
    def __init__(self,glass_image,mouse_image,size):
        pygame.sprite.Sprite.__init__(self)

        self.glass_image = pygame.image.load(glass_image).convert_alpha()
        self.glass_rect  = self.glass_image.get_rect()
        self.glass_rect.left,self.glass_rect.top = \
                        (size[0]-self.glass_rect.width)//2,size[1]-self.glass_rect.height
                        
        self.mouse_image = pygame.image.load(mouse_image).convert_alpha()
        self.mouse_rect = self.mouse_image.get_rect()
        self.mouse_rect.left,self.mouse_rect.top=self.glass_rect.left,self.glass_rect.top
        pygame.mouse.set_visible(False)        
        
        
            
def checkball(item,target):
    check=[]
    for each in target:
        distance=math.sqrt(math.pow(item.rect.center[0]-each.rect.center[0],2)+\
                           math.pow(item.rect.center[1]-each.rect.center[1],2))
        long = (item.rect.width+each.rect.width)/2
        if distance<=long:
            check.append(each)

    return check

    
def main():
    pygame.init()
    pygame.mixer.init()

    Ball_image='gray_ball.png'
    green_image='green_ball.png'
    glass_image='glass.png'
    mouse_image='mouse.png'
    background='background.png'
    balls=[]
    draw= []
    msgs=[]
    group=pygame.sprite.Group()
    BLACK = (255,255,255)
    
    
    size=width,height=1024,681
    screen=pygame.display.set_mode(size)
    pygame.display.set_caption("Play the ball")
    clock=pygame.time.Clock()
    bg=pygame.image.load(background).convert_alpha()
    hole = [(117, 119, 199, 201), (225, 227, 390, 392), \
            (503, 505, 320, 322), (698, 700, 192, 194), \
            (906, 908, 419, 421)]
        
    pygame.mixer.music.load('bg_music.ogg')
    pygame.mixer.music.set_volume(0.2)
    pygame.mixer.music.play()

    hole_sound = pygame.mixer.Sound('hole.wav')
    hole_sound.set_volume(0.2)
    laugh_sound = pygame.mixer.Sound('laugh.wav')
    laugh_sound.set_volume(0.2)
    loser_sound = pygame.mixer.Sound('loser.wav')
    loser_sound.set_volume(0.2)
    winner_sound = pygame.mixer.Sound('winner.wav')
    winner_sound.set_volume(0.2)
    hole_sound = pygame.mixer.Sound('hole.wav')
    hole_sound.set_volume(0.2)

    GAMEOVER = pygame.USEREVENT
    MYTIMER = pygame.USEREVENT+1
    pygame.mixer.music.set_endevent(GAMEOVER)
    pygame.time.set_timer(MYTIMER,1000)
    pygame.key.set_repeat(100,100)
    
    motion = 0
    ball_num=1
    
    for i in range(ball_num):
        position=random.randint(0,width-100),random.randint(0,height-100)
        speed=[random.randint(1,10),random.randint(1,10)]
        target= 5*(i+1)
        ball=Ball(Ball_image,green_image,position,speed,size,target)
        #checkball是自己写的碰撞检测checkball(ball,balls)
        #pygame自带碰撞检查就是 pygame.sprite.spritelcollide
        while pygame.sprite.spritecollide(ball,group,False,pygame.sprite.collide_circle):
            position=random.randint(0,width-100),random.randint(0,height-100)
            ball=Ball(Ball_image,green_image,position,speed,size,target)
            #或者改成
            #ball.rect.left,ball.rect.top=random.randint(0,width-100),random.randint(0,height-100)
        #balls.append(ball)
        group.add(ball)
        draw.append(ball)
    
    glass= Glass(glass_image,mouse_image,size)
    run=True
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == GAMEOVER:
                loser_sound.play()
                pygame.time.delay(2000)
                laugh_sound.play()
                run = False
            elif event.type == MYTIMER:
                if motion:
                    for each in group:
                        if each.check(motion):
                            each.speed=[0,0]
                            each.control = True
                    motion = 0
            elif event.type == pygame.MOUSEMOTION:
                motion+=1

            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_w:
                    for each in group:
                        if each.control:
                            each.speed[1] -=1
                if event.key == pygame.K_s:
                    for each in group:
                        if each.control:
                            each.speed[1] +=1
                if event.key == pygame.K_a:
                    for each in group:
                        if each.control:
                            each.speed[0] -=1
                if event.key == pygame.K_d:
                    for each in group:
                        if each.control:
                            each.speed[0] +=1
                if event.key == pygame.K_SPACE:
                    for each in group:
                        if each.control:
                            for i in hole:
                                if i[0]<=each.rect.left<=i[1] and i[2]<=each.rect.top<=i[3]:
                                    each.speed = [0, 0]
                                    hole_sound.play()
                                    group.remove(each)
                                    draw.remove(each)
                                    draw.insert(0,each)
                                    hole.remove(i)
                            if not group:
                                pygame.mixer.music.stop()
                                winner_sound.play()
                                pygame.time.delay(3000)
                                msg = pygame.image.load("win.png").convert_alpha()
                                msg_pos = (width - msg.get_width()) // 2, \
                                      (height - msg.get_height()) // 2
                                msgs.append((msg, msg_pos))
                                laugh_sound.play()
                
        screen.blit(bg,(0,0))
        screen.blit(glass.glass_image,glass.glass_rect)
        
        glass.mouse_rect.left,glass.mouse_rect.top=pygame.mouse.get_pos()
        
        if glass.mouse_rect.left<glass.glass_rect.left:
            glass.mouse_rect.left=glass.glass_rect.left
        if glass.mouse_rect.right>glass.glass_rect.right:
            glass.mouse_rect.right=glass.glass_rect.right
        if glass.mouse_rect.top<glass.glass_rect.top:
            glass.mouse_rect.top=glass.glass_rect.top
        if glass.mouse_rect.bottom>glass.glass_rect.bottom:
            glass.mouse_rect.bottom=glass.glass_rect.bottom
        screen.blit(glass.mouse_image,glass.mouse_rect)
        
        for each in group:
            each.move()
            if each.collide:
                each.speed=[random.randint(1,10),random.randint(1,10)]
                each.collide = False

        for each in draw:
            if each.control:
                screen.blit(each.green_image,each.rect)
            else: 
                screen.blit(each.Ball_image,each.rect)

        '''for i in range(ball_num):
            item=balls.pop(i)
            if pygame.sprite.spritecollide(item,balls,False,pygame.sprite.collide_circle):
                item.speed[0]=-item.speed[0]
                item.speed[1]=-item.speed[1]
            balls.insert(i,item)'''
        for each in group:
            group.remove(each)
            if pygame.sprite.spritecollide(each,group,False,pygame.sprite.collide_circle):
                if each.control:
                    each.side[0]=-1
                    each.side[1]=-1
                    each.control = False
                else :
                    each.side[0]=-each.side[0]
                    each.side[1]=-each.side[1]
                each.collide = True
                
            group.add(each)
        for msg in msgs:
                    screen.blit(msg[0], msg[1])        
        pygame.display.flip()
        clock.tick(30)
    screen.fill(BLACK)
    pygame.display.flip()  
    clock.tick(30)
if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常，而不是一闪而过！
    try:
        main()
    except SystemExit:
        pass
    except:
        traceback.print_exc()
        pygame.quit()
        input()
    
